package com.browan.constellation.http;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class HttpClient
{

	/**
	 * User-Agent
	 */
	public static final String USER_AGENT_VALUE = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; EmbeddedWB 14.52 from: http://www.bsalsa.com/ EmbeddedWB 14.52; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1; .NET CLR 1.0.3705; .NET CLR 3.0.04506.30)";

	/**
	 * 命令分隔符
	 */
	public static final String HTTP_CLIENT_CMD_SPLITOR = "@@";

	/**
	 * POST 参数分隔符
	 */
	public static final String POST_PARAMETER_SPLITOR = "&";

	/**
	 * POST 参数值分隔符
	 */
	private static final String POST_PARAMETER_KV_SPLITOR = "=";

	/**
	 * 从HTML头中找到编码字段
	 */
	private static Pattern CONTENT_TYPE_CHARSET_PATTERN = Pattern.compile("charset=([-_a-zA-Z0-9]*)");

	/**
	 * 连接超时 默认10秒
	 */
	private static final int CONNECT_TIME_OUT = 10 * 1000;

	/**
	 * 读取超时 默认 10秒
	 */
	private static final int READ_TIME_OUT = 10 * 1000;

	/**
	 * 初始HttpClient 的一个新实例
	 */

	public HttpClient()
	{

	}

	/**
	 * GET 方法请求给定URL，并且返HTTP 响应的内容
	 * 
	 * @param url
	 *            要请求的 URL
	 * @param heads
	 *            请求包含HTTP 头
	 * @param keepCookie
	 *            是否保存 Cookie 信息
	 * @return 给定 URL 返回的响应
	 */
	public String getMethod(String url, String encoding) throws Exception
	{
		if (url == null || url.length() == 0)
		{
			throw (new Exception("Requst url could not be null or empty."));
		}

		String result = null;
		BufferedReader httpBufferedReader = null;
		try
		{
			HttpURLConnection httpURLConnection = getHttpURLConnection(url);
			// Set request properties.
			settingHttpRequestHeader(httpURLConnection);
			httpURLConnection.setRequestMethod("GET");
			httpURLConnection.setDoInput(true);
			// Getting or setting cookie
			httpURLConnection.connect();
			InputStream httpInputStream = httpURLConnection.getInputStream();
			httpBufferedReader = new BufferedReader(new InputStreamReader(httpInputStream, encoding));
			result = readBufferedContent(httpBufferedReader);
		}
		catch (IOException e)
		{
			throw (e);
		}
		finally
		{
			if (null != httpBufferedReader)
			{
				close(httpBufferedReader);
			}
		}
		return result;
	}

	public String postMethod(String url, Map<String, String> parameters, String encoding) throws Exception
	{

		String postResponse = null;
		HttpURLConnection httpURLConnection = null;
		OutputStream httpOutputStream = null;
		try
		{
			// Build post parameters string
			StringBuffer postParams = new StringBuffer();
			if (parameters != null)
			{
				int index = 0;
				for (Iterator<Entry<String, String>> iter = parameters.entrySet().iterator(); iter.hasNext(); index++)
				{
					Entry<String, String> entry = iter.next();
					postParams.append(index != 0 ? POST_PARAMETER_SPLITOR : "");
					postParams.append(entry.getKey());
					postParams.append(POST_PARAMETER_KV_SPLITOR);
					postParams.append(entry.getValue());
				}
			}
			httpURLConnection = getHttpURLConnection(url);
			// Set request properties.
			settingHttpRequestHeader(httpURLConnection);
			// Set request method with 'POST'
			httpURLConnection.setRequestMethod("POST");
			httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			// application/x-www-form-urlencoded;charset=UTF-8
			// Set connection output is true.
			httpURLConnection.setDoOutput(true);

			httpURLConnection.setRequestProperty("Content-Length", String.valueOf(postParams.toString().length()));

			// Get Http output stream

			// int recode = httpURLConnection.getResponseCode();
			// System.out.println(recode);
			// System.out.println(httpURLConnection.getResponseCode());

			httpOutputStream = httpURLConnection.getOutputStream();
			httpOutputStream.write(postParams.toString().getBytes());
			// Getting or setting cookie

			if (null == encoding)
			{
				String contentType = httpURLConnection.getContentType();
				Matcher matcher = CONTENT_TYPE_CHARSET_PATTERN.matcher(contentType);
				if (matcher.find())
				{
					encoding = matcher.group(1);
				}
			}
			InputStream inputStream = httpURLConnection.getInputStream();
			ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
			byte[] buffer = new byte[8192];
			int size = -1;
			while ((size = inputStream.read(buffer)) != -1)
			{
				byteStream.write(buffer, 0, size);
			}
			byte[] data = byteStream.toByteArray();
			if (encoding != null)
			{
				postResponse = new String(data, encoding);
			}
			else
			{
				postResponse = new String(data, "utf-8");
			}
		}
		finally
		{
			if (null != httpOutputStream)
				try
				{
					httpOutputStream.close();
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
		}

		return postResponse;

	}

	/**
	 * Setting HTTP request header properties
	 * 
	 * @param httpURLConnection
	 */
	private void settingHttpRequestHeader(HttpURLConnection httpURLConnection)
	{
		httpURLConnection.setConnectTimeout(CONNECT_TIME_OUT);
		httpURLConnection.setReadTimeout(READ_TIME_OUT);
		httpURLConnection.setRequestProperty("User-Agent", USER_AGENT_VALUE);
		// TODO setting some other properties here . . .
	}

	/**
	 * Get HttpURLConnection by specified url string.
	 * 
	 * @param url
	 * @return
	 * @throws IOException
	 */
	private HttpURLConnection getHttpURLConnection(String url) throws IOException
	{
		URL urlObj = new URL(url);
		URLConnection urlConnection = urlObj.openConnection();
		if (urlConnection instanceof HttpURLConnection)
			return (HttpURLConnection) urlConnection;
		throw new MalformedURLException();
	}

	/**
	 * Read bufferedReader buffered content.
	 * 
	 * @param bufferedReader
	 * @return
	 */
	private String readBufferedContent(BufferedReader bufferedReader)
	{
		if (bufferedReader == null)
			return null;
		StringBuffer result = new StringBuffer();
		String line = null;
		try
		{
			while ((line = bufferedReader.readLine()) != null)
			{
				result.append(line);
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
			return null;
		}
		return result.toString();
	}

	public void close(Object stream)
	{
		if (null != stream)
		{

			if (stream instanceof Closeable)
			{
				try
				{
					((Closeable) stream).close();
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}

			}
		}
	}

}